package com.zrrd.yt.cart.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zrrd.yt.cart.mapper.CartInfoMapper;
import com.zrrd.yt.cart.service.CartAsyncService;
import com.zrrd.yt.cart.service.CartInfoService;
import com.zrrd.yt.model.cart.CartInfo;
import com.zrrd.yt.model.product.SkuInfo;
import com.zrrd.yt.product.client.ProductFeigClient;
import com.zrrd.yt.service.constant.RedisConst;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 思路分析
 * 根据sku查询购物车中是否有该商品
 * 有：
 * 更新购物车商品
 * 1、商品数量+本次添加的商品数量
 * 2、设置商品最新价格
 * 3、设置更新时间
 * 4、执行更新
 * 没有：
 * 添加商品到购物车
 * 1、根据skuid去商品服务中查询商品详情
 * 2、创建购物车对象
 * 3、根据获取到的商品信息 给购物车对象属性分别赋值
 * 4、设置创建时间和更新时间
 * 5、执行添加
 */
@Service
public class CartInfoServiceImpl extends ServiceImpl<CartInfoMapper, CartInfo> implements CartInfoService {

    @Autowired
    private ProductFeigClient productFeigClient;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private CartAsyncService cartAsyncService;

    //添加购物车
    @Override
    public void addToCart(Long skuId, String userId, Integer skuNum) {
        //如果缓存中 没有该key
        if (!redisTemplate.hasKey(this.getCartKey(userId))) {
            //查询数据库的数据并且加入缓存
            this.getCartInfoByDB(userId);
        }
        //从缓存中查询出指定数据
        CartInfo cartInfo = (CartInfo) redisTemplate.boundHashOps(this.getCartKey(userId)).get(skuId.toString());
        //判断是否有该数据
        if (cartInfo != null) {
            cartInfo.setSkuNum(cartInfo.getSkuNum() + skuNum);
            cartInfo.setSkuPrice(productFeigClient.getSkuPrice(skuId));
            cartInfo.setUpdateTime(new Timestamp(System.currentTimeMillis()));
            //执行更新
            cartAsyncService.updateCartInfo(cartInfo);
        } else {
            SkuInfo skuInfo = productFeigClient.getSkuInfo(skuId);
            cartInfo = new CartInfo();
            cartInfo.setSkuId(skuId);
            cartInfo.setUserId(userId);
            cartInfo.setCartPrice(skuInfo.getPrice());
            cartInfo.setSkuPrice(productFeigClient.getSkuPrice(skuId));
            cartInfo.setSkuNum(skuNum);
            cartInfo.setSkuName(skuInfo.getSkuName());
            cartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
            cartInfo.setCreateTime(new Timestamp(System.currentTimeMillis()));
            cartInfo.setUpdateTime(new Timestamp(System.currentTimeMillis()));
            //执行添加
            cartAsyncService.saveCartInfo(cartInfo);
        }

        //将数据存入到Redis
        redisTemplate.opsForHash().put(this.getCartKey(userId), skuId.toString(), cartInfo);
        this.setCartKeyExpire(this.getCartKey(userId));
    }

    //查询购物车
    @Override
    public List<CartInfo> getCartList(String userId, String userTempId) {
        //新建最终返回的集合对象
        List<CartInfo> cartInfoList = new ArrayList<>();
        //未登录：根据临时用户ID获取购物车数据
        if (StringUtils.isEmpty(userId)) {
            cartInfoList = this.getCartList(userTempId);
            return cartInfoList;
        }
        //已登录：进行合并操作
        if (!StringUtils.isEmpty(userId)) {
            //获取临时购物车数据
            List<CartInfo> cartTempList = this.getCartList(userTempId);
            //非空判断
            if (!CollectionUtils.isEmpty(cartTempList)) {
                //将临时的购物车数据合并到当前登录用户的购物车数据
                cartInfoList = this.mergeToCartList(cartTempList, userId);
                //删除临时购物车数据
                this.deleteCartList(userTempId);
            }
            //如果临时购物车没有数据 返回登录用户购物车数据
            if (StringUtils.isEmpty(userTempId) || CollectionUtils.isEmpty(cartTempList)) {
                cartInfoList = this.getCartList(userId);
            }
        }
        return cartInfoList;
    }

    //更新选中状态
    @Override
    public void chekCart(String userId, Long skuId, Integer isChecked) {
        //异步更新Mysql
        cartAsyncService.chekCart(userId, skuId, isChecked);
        //更新Redis缓存
        String cartKey = this.getCartKey(userId);
        //根据大key获取整个对象
        BoundHashOperations<String, String, CartInfo> ops = redisTemplate.boundHashOps(cartKey);
        //判断是否包含指定的小key
        if (ops.hasKey(skuId.toString())) {
            //根据小key获取指定数据
            CartInfo cartInfo = ops.get(skuId.toString());
            //给对象设置选中属性
            cartInfo.setIsChecked(isChecked);
            //更新缓存(重新存入)
            ops.put(skuId.toString(),cartInfo);
            //设置过期时间
            this.setCartKeyExpire(cartKey);
        }
    }

    //删除购物车中指定商品
    @Override
    public void deleteCartOne(String userId, Long skuId) {
        //异步删除Mysql
        cartAsyncService.deleteCartOne(userId,skuId);
        //删除redis的数据
        String cartKey = this.getCartKey(userId);
        BoundHashOperations ops = redisTemplate.boundHashOps(cartKey);
        if(ops.hasKey(skuId.toString())){
            ops.delete(skuId.toString());
        }
    }

    //获取选中商品
    @Override
    public List<CartInfo> getCheckedCartList(String userId) {
        //创建最终返回的购物车列表
        List<CartInfo> cartInfoList = new ArrayList<>();
        //从缓存中查询用户的购物车数据
        List<CartInfo> cartCacheList = redisTemplate.opsForHash().values(this.getCartKey(userId));
        //遍历集合
        if(!CollectionUtils.isEmpty(cartCacheList)){
            for (CartInfo cartInfo : cartCacheList) {
                //如果当前遍历的购物车对象 选中状态为1 添加进最终的返回集合中
                if(cartInfo.getIsChecked().intValue() == 1){
                    cartInfoList.add(cartInfo);
                }
            }
        }
        //返回数据
        return cartInfoList;
    }

    //合并购物车的方法
    private List<CartInfo> mergeToCartList(List<CartInfo> cartTempList, String userId) {
        //根据登录用户id查询购物车列表
        List<CartInfo> cartList = this.getCartList(userId);
        //将集合转为拆分成map集合 key==>skuId  value==>当前购物车数据对象
        Map<Long, CartInfo> cartMap = cartList.stream().collect(Collectors.toMap(CartInfo::getSkuId, cartInfo -> cartInfo));
        //遍历临时购物车集合
        for (CartInfo cartInfo : cartTempList) {
            //获取当前购物车对象的skuid
            Long skuId = cartInfo.getSkuId();
            //判断map集合中是否包含指定的key
            if (cartMap.containsKey(skuId)) {
                //根据key获取登录用户的购物车对象
                CartInfo cart = cartMap.get(skuId);
                //设置数量
                cart.setSkuNum(cart.getSkuNum() + cartInfo.getSkuNum());
                cart.setUpdateTime(new Timestamp(System.currentTimeMillis()));
                //执行更新
                QueryWrapper<CartInfo> wrapper = new QueryWrapper<>();
                wrapper.eq("user_id", userId);
                wrapper.eq("sku_id", skuId);
                this.update(cart, wrapper);
            } else {
                cartInfo.setUserId(userId);
                cartInfo.setCreateTime(new Timestamp(System.currentTimeMillis()));
                cartInfo.setUpdateTime(new Timestamp(System.currentTimeMillis()));
                //执行保存
                this.save(cartInfo);
            }
        }
        //查询数据库 并且存入缓存
        List<CartInfo> cartInfoList = this.getCartInfoByDB(userId);
        return cartInfoList;
    }

    //删除临时购物车
    private void deleteCartList(String userTempId) {
        //删除Mysql的数据
        cartAsyncService.deleteCartInfo(userTempId);
        //删除Redis的数据
        String cartKey = this.getCartKey(userTempId);
        if (redisTemplate.hasKey(cartKey)) {
            redisTemplate.delete(cartKey);
        }
    }

    //获取购物车数据的方法
    private List<CartInfo> getCartList(String userId) {
        //创建最终返回的集合
        List<CartInfo> cartInfoList = new ArrayList<>();
        //从缓存中获取数据
        String cartKey = this.getCartKey(userId);
        cartInfoList = redisTemplate.opsForHash().values(cartKey);
        //判断缓存中是否有数据
        if (!CollectionUtils.isEmpty(cartInfoList)) {
            //直接返回
            return cartInfoList;
        } else {
            //查询数据库
            cartInfoList = this.getCartInfoByDB(userId);
        }
        return cartInfoList;
    }

    //从数据库中获取购物车数据
    public List<CartInfo> getCartInfoByDB(String userId) {
        //条件查询
        QueryWrapper<CartInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId);
        List<CartInfo> cartInfoList = this.list(wrapper);
        //非空判断
        if (CollectionUtils.isEmpty(cartInfoList)) {
            return cartInfoList;
        }
        //创建HashMap集合 用于存入数据
        HashMap<String, CartInfo> map = new HashMap<>();
        //遍历从数据库中查询的购物车列表
        for (CartInfo cartInfo : cartInfoList) {
            //设置一下最新价格
            cartInfo.setSkuPrice(productFeigClient.getSkuPrice(cartInfo.getSkuId()));
            System.out.println("存入缓存的最新价格====>" + productFeigClient.getSkuPrice(cartInfo.getSkuId()));
            //添加进map集合
            map.put(cartInfo.getSkuId().toString(), cartInfo);
        }
        //将map集合作为hash对象存入redis
        String cartKey = this.getCartKey(userId);
        redisTemplate.opsForHash().putAll(cartKey, map);
        this.setCartKeyExpire(cartKey);
        return cartInfoList;
    }


    //定义缓存的key
    private String getCartKey(String userId) {
        //user:4:cart
        return RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
    }

    //定义缓存的过期时间
    private void setCartKeyExpire(String cartKey) {
        redisTemplate.expire(cartKey, RedisConst.USER_CART_EXPIRE, TimeUnit.SECONDS);
    }
}
